﻿using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using nanoCMS.Core.Concrete;
using nanoCMS.Core.Extensions;
using nanoCMS.Core.Providers;
using nanoCMS.Core.WebProviders.ViewModels;

namespace nanoCMS.Core.WebProviders {
	public enum PageSections
	{
		Main = 1,
		AsideFirst = 2,
		AsideSecond = 3,
		Navigation = 4,
		BeforeContent = 5,
		AfterContent = 6,
		Footer = 7
	}

	public class PageProvider {
		private readonly WorldContext worldContext;
		private ViewElementProvider _viewElementProvider;
		private CacheProvider _cacheProvider;
		private const string StaticPagesCacheKey = "StaticPageStructure";
		private const string StaticPagesUrlsCacheKey = "StaticPageUrlsData";

		public PageProvider(WorldContext worldContext) {
			this.worldContext = worldContext;
			_viewElementProvider = new ViewElementProvider(worldContext);
			_cacheProvider = worldContext.CacheProvider;
		}


		private bool IsUrlInUse(string relativeUrl, int? tenantID = null) {
			tenantID = tenantID.IfNullSet(WorldContext.TenantID);
			return worldContext.Entities.TenantPages.Any(x => x.RelativeURL == relativeUrl && x.TenantID == tenantID);
		}

		private int GetDefaultPageTemplate(int? tenantID = null) {
			tenantID = tenantID.IfNullSet(WorldContext.TenantID);
			var template =
				 worldContext.Entities.TenantPageTemplates.SingleOrDefault(
					  x => x.TenantID == tenantID && x.IsDefault == true);
			if (template == null) throw new Exception("No default theme for tenantID=" + tenantID);

			return template.IDPageTemplate;
		}


		public TenantPage AddPage(string link, int? pageTemplateId = null, string title = null, int? tenantId = null) {
			//TODO: find first available
			if (IsUrlInUse(link)) return null;
			tenantId = tenantId.IfNullSet(WorldContext.TenantID);
			pageTemplateId = pageTemplateId.IfNullSet(GetDefaultPageTemplate(tenantId));

			TenantPage tenantPage = new TenantPage {
				TenantID = (int)tenantId,
				RelativeURL = link,
				TenantPageTemplateID = (int)pageTemplateId,
			};

			worldContext.Entities.TenantPages.AddObject(tenantPage);
			worldContext.Entities.SaveChanges();
			return tenantPage;
		}

		#region build page data
		private void AddSiteMetaTags(int tenantId, ref WebDisplayVM model)
		{
			//if (model == null) model = new WebDisplayVM();
			
			MetaTagProvider metaTagProvider = new MetaTagProvider(worldContext.Entities);
			TenantMetatag metaTags = metaTagProvider.Get(tenantId);

			model.Title = metaTags.Title;
			model.Description = metaTags.Description;
		}


		private bool IsLinkStatic(string link)
		{
			if (!_cacheProvider.Contains(StaticPagesUrlsCacheKey))
			{
				List<string> data = worldContext.Entities.StaticPageStructures.Select( x=>x.PageUrl ).ToList();
				_cacheProvider.Add(StaticPagesUrlsCacheKey, data);
			}

			List<string> cacheData = _cacheProvider.Get(StaticPagesUrlsCacheKey) as List<string>;
			if (cacheData == null) throw new Exception("Can't access memory");
			return (cacheData).Contains(link);
		}
		#endregion


		public WebDisplayVM GetDisplayData(string link) {
			WebDisplayVM displayModel = new WebDisplayVM();
			if (IsLinkStatic(link))
			{
				int defaultTemplateID = GetDefaultPageTemplate(RequestItems.TenantID);

				displayModel.Main = _viewElementProvider.GetStaticSectionMain(link);
				displayModel.AsideFirst = _viewElementProvider.GetStaticSection(defaultTemplateID, PageSections.AsideFirst);
				displayModel.AsideSecond = _viewElementProvider.GetStaticSection(defaultTemplateID, PageSections.AsideSecond);
				displayModel.Navigation = _viewElementProvider.GetStaticSection(defaultTemplateID, PageSections.Navigation);
				displayModel.BeforeContent = _viewElementProvider.GetStaticSection(defaultTemplateID, PageSections.BeforeContent);
				displayModel.AfterContent = _viewElementProvider.GetStaticSection(defaultTemplateID, PageSections.AfterContent);
				displayModel.Footer = _viewElementProvider.GetStaticSection(defaultTemplateID, PageSections.Footer);

			} else
			{
				TenantPage page = GetPage(link, RequestItems.TenantID);
				displayModel.Main = _viewElementProvider.GetSection(page.IDTenantPage, page.TenantPageTemplateID,
				                                                    Convert.ToInt32(PageSections.Main));
				displayModel.AsideFirst = _viewElementProvider.GetSection(page.IDTenantPage, page.TenantPageTemplateID,
				                                                          Convert.ToInt32(PageSections.AsideFirst));
				displayModel.AsideSecond = _viewElementProvider.GetSection(page.IDTenantPage, page.TenantPageTemplateID,
				                                                           Convert.ToInt32(PageSections.AsideSecond));
				displayModel.Navigation = _viewElementProvider.GetSection(page.IDTenantPage, page.TenantPageTemplateID,
				                                                          Convert.ToInt32(PageSections.Navigation));
				displayModel.BeforeContent = _viewElementProvider.GetSection(page.IDTenantPage, page.TenantPageTemplateID,
				                                                             Convert.ToInt32(PageSections.BeforeContent));
				displayModel.AfterContent = _viewElementProvider.GetSection(page.IDTenantPage, page.TenantPageTemplateID,
				                                                            Convert.ToInt32(PageSections.AfterContent));
				displayModel.Footer = _viewElementProvider.GetSection(page.IDTenantPage, page.TenantPageTemplateID,
				                                                      Convert.ToInt32(PageSections.Footer));
			}
			AddSiteMetaTags(RequestItems.TenantID, ref displayModel);

			return displayModel;
		}


		/// <summary>
		/// Get page for the link, if not found return default
		/// </summary>
		/// <param name="link"></param>
		/// <param name="tenantId"></param>
		/// <returns></returns>
		public TenantPage GetPage(string link, int? tenantId = null) {
			tenantId = tenantId.IfNullSet(RequestItems.TenantID);
			TenantPage page =
				 worldContext.Entities.TenantPages.SingleOrDefault(x => x.TenantID == tenantId && x.RelativeURL == link);

			return page ?? worldContext.Entities.TenantPages.SingleOrDefault(
				 x => x.TenantID == tenantId && x.IsDefault);
		}
	}
}
